//JDK 1.4 Tutorial.pdf: page 46~50
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;

public class PollingChatServer implements Runnable {
	
	static private final int sleepTime = 100; //SLEEP_TIME
	private int port;
	private Vector sockets = [];
	private Set closedSockets = new HashSet();

	public PollingChatServer(int port) {
		this.port = port;
	}
	
	public void run() {
		
		try {
			ServerSocketChannel ssc = ServerSocketChannel.open();
			ssc.configureBlocking(false);
			ServerSocket ss = ssc.socket();
			InetSocketAddress isa = new InetSocketAddress(port);
			ss.bind(isa);
			
			ByteBuffer buffer = ByteBuffer.allocate(4096);
			println "PollingChatServer: Listening on port ${port}" 
			while (true) {
				SocketChannel sc = ssc.accept();
				if (sc != null) {
					Socket newSocket = sc.socket();
					println "Connection from " + newSocket
					newSocket.getChannel().configureBlocking(false);
					sockets.add(newSocket);
				}
				sockets.each { socket ->
					try {
						SocketChannel sch = socket.getChannel();
						buffer.clear();
						sch.read(buffer);
						if (buffer.position() > 0) {
							buffer.flip();
							println "Read " + buffer.limit() + " bytes from ${sch.socket()}"
							sendToAll(buffer);
						}
					} catch(IOException ie) {
						closedSockets.add(socket);
					}
				}
				removeClosedSockets();
				try {
					Thread.sleep(sleepTime);
				} catch(InterruptedException ie) {}
			}
		} catch(IOException ie) {
			ie.printStackTrace();
		}
	}

	private void sendToAll(ByteBuffer bb) {

		sockets.each { socket ->
			try {
				println "send to ${socket}"
				SocketChannel sc = socket.getChannel();
				bb.rewind();
				while (bb.remaining()>0) {
					sc.write(bb);
				}
			} catch(IOException ie) {
				closedSockets.add(socket);
			}
		}
	}
	
	private void removeClosedSockets() {
		
		closedSockets.each { socket ->
			sockets.remove(socket);
			System.out.println("Removed "+socket);
		}
		closedSockets.clear();
	}
	
	static public void main(def args) throws Exception {
		
		Thread t = new Thread(new PollingChatServer(5555), "PollingChatServer");
		t.start();
	}
}